#include <iostream>
#include <thread>
#include <unistd.h>
#include <semaphore.h>
using namespace std;
class Foo
{
private:
    sem_t semFirstDone, semSecondDone;
public:
    Foo()
    {
        /*
        功能 创建一个信号量并初始化它的值，一个无名信号量在被使用前必须初始化
        参数 sem 信号量地址
            pshared  等于0 信号量在线程间共享   不等于0 信号在进程间共享
            value 信号量的初始值
        返回 成功 0    失败 -1
        */
        cout << "Foo()" << endl;
        if (sem_init(&semFirstDone, 0, 0) == -1)
        {
            cout << "sem_init semFirstDone fail!" << endl;
        }
        if (sem_init(&semSecondDone, 0, 0) == -1)
        {
            cout << "sem_init semSecondDone fail!" << endl;
        }
    }
    ~Foo()
    {
        cout << "~Foo()" << endl;
        if (sem_destroy(&semFirstDone) == -1)
        {
            cout << "sem_init semFirstDone fail!" << endl;
        }
        if (sem_destroy(&semSecondDone) == -1)
        {
            cout << "sem_init semSecondDone fail!" << endl;
        }
    }
    void first()
    {
        cout << "first";
        sem_post(&semFirstDone);
    }
    void second()
    {
        sem_wait(&semFirstDone);
        cout << "second";
        sem_post(&semSecondDone);
    }
    void third()
    {
        sem_wait(&semSecondDone);
        cout << "third";
    }
};

int main()
{
    /*
        在Linux下有缓冲区这个概念，缓冲区满或者是换行才会输出，目的是提高效率
        但如果不想这样，解决方法：
        1、在printf里加"\n"
        2、fflush(stdout)刷新标准输出缓冲区，把输出缓冲区里的东西打印到标准输出设备上 。
        3、setvbuf(stdout,NULL,_IONBF,0)，如果你嫌上个方法麻烦, 就使用这个函数，禁止缓冲区
    */
    setvbuf(stdout, NULL, _IONBF, 0);  
    Foo foo;
    /*
        如果传入进程函数的不是地址，传入时就会调用一次析构函数，当线程结束，又会再次调用一次析构函数,因为是浅拷贝了一份，传入的与外面的不是同一个
        而如果传入的是地址不会执行析构函数
    */
    thread t1(&Foo::first, &foo);
    thread t2(&Foo::second, &foo);
    thread t3(&Foo::third, &foo);
    while (1)
    {
        printf("1\n");
        sleep(1);
    }
    t1.join();
    t2.join();
    t3.join();
    return 0;
}